/**
 * Create in 2012-4-12.
 */
package kit4j.jdbc.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * 通用的Hibernate会话工厂的封装类，该类型意图提供获取线程安全且资源利用效率更高的Session。
 * 
 * @author MiniKnife
 * 
 */
public class HibernateSessionFactory {

	/**
	 * 默认的Hibernate配置文件路径。
	 */
	private static final String DEFAULT_HIBERNATE_CONFIG_FILE = "hibernate.cfg.xml";

	/**
	 * 线程局部变量。
	 */
	private static ThreadLocal<Session> threadLocal;

	/**
	 * Hibernate配置对象。
	 */
	private static Configuration configuration;

	/**
	 * Hibernate配置文件路径。
	 */
	private static String hibernateConfigFile;

	/**
	 * Hibernate的会话工厂。
	 */
	private static SessionFactory sessionFactory;

	/**
	 * 单例对象持有者。
	 * 
	 * @author MiniKnife
	 * 
	 */
	private static class SingletonHolder {
		/**
		 * HibernateSessionFactory的唯一实例。
		 */
		private static HibernateSessionFactory instance = new HibernateSessionFactory();
	}

	/**
	 * 创建一个HibernateSessionFactory对象。
	 */
	private HibernateSessionFactory() {
		threadLocal = new ThreadLocal<Session>();
		configuration = buildConfiguration();
		sessionFactory = buildSessionFactory();
	}

	/**
	 * 创建Hibernate的配置对象。如果在该方法调用前没有调用{@link #configure(String)}方法，则使用 {@link #DEFAULT_HIBERNATE_CONFIG_FILE
	 * DEFAULT_HIBERNATE_CONFIG_FILE}对配置对象进行配置。
	 * 
	 * @return Hibernate的配置对象
	 */
	private Configuration buildConfiguration() {
		if (hibernateConfigFile == null) {
			hibernateConfigFile = DEFAULT_HIBERNATE_CONFIG_FILE;
		}

		return new Configuration().configure(hibernateConfigFile);
	}

	/**
	 * 创建Hibernate的会话工厂对象。
	 * 
	 * @return 会话工厂对象
	 */
	private SessionFactory buildSessionFactory() {
		return configuration.buildSessionFactory();
	}

	/**
	 * 使用指定路径的文件配置Hibernate的配置对象，仅在第一次调用方法{@link #getSession()}前有效。
	 * 
	 * @param configFile
	 */
	public static void configure(String configFile) {
		hibernateConfigFile = configFile;
	}

	/**
	 * @return 从Hibernate的会话工厂中获取的当前线程的局部Session对象。
	 */
	public static Session getSession() throws HibernateException {
		initHibernateSessionFactory();

		Session session = threadLocal.get();

		if (session == null || !session.isOpen()) {
			session = sessionFactory.openSession();
			threadLocal.set(session);
		}

		return session;
	}

	/**
	 * @return 初始化HibernateSessionFactory的唯一实例。
	 */
	private static HibernateSessionFactory initHibernateSessionFactory() {
		return SingletonHolder.instance;
	}
	
	public static void destroySession() throws HibernateException {
		Session session = threadLocal.get();
		
		if(session != null) {
			session.close();
		}
		
		threadLocal.set(null);
	}

}
